package org.deyang.tools.amazon;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;
import java.util.logging.Logger;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.deyang.tools.amazon.exceptions.KeepaContentException;
import org.deyang.tools.amazon.pojos.PriceInformation;
import org.deyang.tools.amazon.pricetracker.KeepaPriceAnalyzer;
import org.deyang.tools.amazon.utils.AmazonXMLProcessor;
import org.deyang.tools.amazon.utils.GlobalConstants;
import org.deyang.tools.amazon.utils.PriceUtils;
import org.deyang.tools.amazon.utils.SignedRequestsHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Text;

public class CheckNewArrivalsServlet extends HttpServlet {
	/**
	 * 
	 */
	private static final long serialVersionUID = -1591230134509972428L;
	private static final Logger log = Logger.getLogger(CheckNewArrivalsServlet.class.getName());

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
	throws IOException {
		/*
         * Set up the signed requests helper 
         */
        SignedRequestsHelper helper = null;
        try {
            helper = SignedRequestsHelper.getInstance(GlobalConstants.ENDPOINT, GlobalConstants.AWS_ACCESS_KEY_ID, GlobalConstants.AWS_SECRET_KEY);
        } catch (Exception e) {
            e.printStackTrace();
            resp.setStatus(403);
        }   
		//Retrieve RSS list from datastore
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        
		Query rssquery = new Query("TrackNodeID");
		Iterator<Entity> rssit = datastore.prepare(rssquery).asIterator();
		
		TreeSet<String> nodeIDSet = new TreeSet<String>();
		
		try {
			int totalNewEntities = 0;
			while (rssit.hasNext()){
				Entity rsslinkEntity = rssit.next();
				String idStr = (String) rsslinkEntity.getProperty("id");
				
				//If id is null or id already exist in previous TrackNodeID record, then delete this duplicate record
				if (idStr == null || !nodeIDSet.add(idStr)){
					log.warning(idStr + " is duplicated in TrackNodeID");
					datastore.delete(rsslinkEntity.getKey());
					continue;
				}
				
				Map<String, String> params = new HashMap<String, String>();
		        params.put("Service", GlobalConstants.SERVICE_NAME);
		        params.put("AssociateTag", GlobalConstants.ASSOCIATE_TAG);
		        params.put("Operation", "BrowseNodeLookup");
		        params.put("BrowseNodeId", idStr);
		        params.put("ResponseGroup", "NewReleases,TopSellers,MostWishedFor");
		        
		        String requestUrl = helper.sign(params);
		        URL url = new URL(requestUrl);
		        
		        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();				
	        	Document domDoc;
				try {
					DocumentBuilder db = dbf.newDocumentBuilder();
					domDoc = db.parse(url.openStream());
				} catch (ParserConfigurationException e1) {
					log.warning(e1.getMessage());
					continue;
				} catch (SAXException e1) {
					log.warning(e1.getMessage());
					continue;
				}
				
				Element browserNodeElement = AmazonXMLProcessor.getDefaultChildNode(domDoc.getDocumentElement(),"BrowseNode");
				
				if (browserNodeElement == null){
					//In this case this is not a valide browse node id, delete it
					datastore.delete(rsslinkEntity.getKey());
				}else if (rsslinkEntity.getProperty("name") == null || ((String)rsslinkEntity.getProperty("name")).trim().equals("")){ //If name is not input via web client, add it here
					rsslinkEntity.setProperty("name", AmazonXMLProcessor.getDefaultChildNodeValue((Element) browserNodeElement, "Name"));
					datastore.put(rsslinkEntity);
				}
				
				totalNewEntities = totalNewEntities + addCategoryProducts(browserNodeElement, "NewReleases", "NewRelease", helper);
				totalNewEntities = totalNewEntities + addCategoryProducts(browserNodeElement, "TopSellers", "TopSeller", helper);
								
			}
			log.warning("" + totalNewEntities + " new arrivals has been added to datastore.");
        	resp.setStatus(200);
		} catch (MalformedURLException e) {
        	resp.setStatus(401);
			e.printStackTrace();
		}
		
	}
	
	private int addCategoryProducts(Element browserNodeElement, String nodeResponseGroup, String itemTagName, SignedRequestsHelper helper){
		Element nodeGroup = AmazonXMLProcessor.getDefaultChildNode(browserNodeElement, nodeResponseGroup);
		NodeList itemList = nodeGroup.getElementsByTagName(itemTagName);
		
		//Build up query ids string
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < itemList.getLength() && i < 10; i++){
			if (i != 0){
				sb.append(",");
			}
			Element item = (Element) itemList.item(i);
			sb.append(AmazonXMLProcessor.getDefaultChildNodeValue(item, "ASIN"));
		}
		
		int count = 0;
		
		Map<String, String> params = new HashMap<String, String>();
        params.put("Service", GlobalConstants.SERVICE_NAME);
        params.put("AssociateTag", GlobalConstants.ASSOCIATE_TAG);
        params.put("Operation", "ItemLookup");
        params.put("ItemId", sb.toString());
        params.put("Availability", "Available");
        params.put("MerchantId", "Amazon");
        params.put("ResponseGroup", "Medium,Offers,OfferFull,Variations");
        
        
        String requestUrl = helper.sign(params);
        
        Document domDoc = null;
        try {
        	URL url = new URL(requestUrl);
        	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        	DocumentBuilder db = dbf.newDocumentBuilder();
			domDoc = db.parse(url.openStream());
		} catch (ParserConfigurationException e1) {
			log.warning(e1.getMessage());
			return 0;
		} catch (SAXException e1) {
			log.warning(e1.getMessage());
			return 0;
		} catch (IOException e) {
			log.warning(e.getMessage());
			return 0;
		}
    	NodeList aItemList = domDoc.getElementsByTagName("Item");
    	DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    	
    	for (int i = 0; i < aItemList.getLength(); i++){
    		Query productQ = new Query("AmazonProduct");	
    		Element itemElement = (Element) aItemList.item(i);
			PriceInformation pi = PriceUtils.getCurrentLowPrice(itemElement, true);
			if (!pi.isAmazonPriceAvailable()){
				continue; //No amazon price available, it means it is a third party product, currently we don't support it
			}
    		
    		String asin = AmazonXMLProcessor.getDefaultChildNodeValue((Element) itemElement, "ASIN");
    		productQ.addFilter("asin", Query.FilterOperator.EQUAL, asin);
    		PreparedQuery pq = datastore.prepare(productQ);
    		Iterator<Entity> iter = pq.asIterator();
    		if (!iter.hasNext()){
    			//In case this product is not recorded in db, add it into db
    			count++;
    			
    			Entity resultEntity = new Entity("AmazonProduct");
    			Element mediumImageElement = AmazonXMLProcessor.getDefaultChildNode(itemElement, "MediumImage");
    			Element arrtElement = AmazonXMLProcessor.getDefaultChildNode(itemElement, "ItemAttributes");
    			
    			resultEntity.setProperty("asin", asin);
    			try {
					KeepaPriceAnalyzer kpa = new KeepaPriceAnalyzer(asin);
					resultEntity.setProperty("PriceHistoryData",new Text(kpa.getAmazonPriceHistoryStr()));
				} catch (KeepaContentException e) {
					//No existing keepa price
				}
    			resultEntity.setProperty("imgurl",AmazonXMLProcessor.getDefaultChildNodeValue(mediumImageElement, "URL"));
    			resultEntity.setProperty("amazonProductTitle", AmazonXMLProcessor.getDefaultChildNodeValue(arrtElement, "Title"));
    			resultEntity.setProperty("trackStatus", "T");
    			String urlStr = AmazonXMLProcessor.getDefaultChildNodeValue(itemElement, "DetailPageURL");
    			if (urlStr.length() >= 500){
    				resultEntity.setProperty("shorturl", new Text(urlStr));
    			}else{
    				resultEntity.setProperty("shorturl", urlStr);	
    			}
    			log.info("Add new arrival " + asin + " to track list.");
    			datastore.put(resultEntity);
    		}
    	}
    	return count;
	}
	
	

}
